<!-- 按部门勾选数据权限 -->
<!--created by yuyupeng 2023/4/19-->
<template>
  <div>
    <a-spin :loading="loadingDept">
      <a-tree
        :checked-keys="checkedNodeKeys"
        :data="deptTreeData"
        checkable
        :field-names="{
          key: 'id',
          title: 'name',
          children: 'children',
          icon: 'checkable',
        }"
        @check="onCheck"
      />
    </a-spin>
  </div>
</template>

<script lang="ts" setup>
  import { ref, watch, defineExpose, PropType } from 'vue';
  import { TreeNodeData, Notification } from '@arco-design/web-vue';
  import { queryDeptRecordTreeList } from '@/api/system/dept';

  const props = defineProps({
    dataScopeDeptIds: {
      // 数据权限范围对应的部门id，格式为1,2,3,4
      type: Array as PropType<string[]>,
      required: true,
    },
  });
  const emits = defineEmits(['change']);

  const loadingDept = ref<boolean>(false);

  const deptTreeData = ref<TreeNodeData[]>([]);
  const currentDataScopeDeptIds = ref<string[]>([]);
  const checkedNodeKeys = ref<string[]>([]);
  const halfCheckedNodeKeys = ref<string[]>([]);
  const onCheck = (
    checkedKeys: (string | number)[],
    { halfCheckedKeys }: { halfCheckedKeys: (string | number)[] }
  ) => {
    checkedNodeKeys.value = [...(checkedKeys as string[])];
    halfCheckedNodeKeys.value = [...halfCheckedKeys] as string[];
    emits('change', checkedNodeKeys.value);
  };
  /**
   * 获取部门树形结构
   */
  const getDeptTree = async () => {
    loadingDept.value = true;
    try {
      const { data } = await queryDeptRecordTreeList({});
      deptTreeData.value = data;
      getDataScopeDeptIdList();
    } catch (error) {
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      Notification.error({
        content: `出现异常！${error}`,
        closable: true,
        duration: 20000,
      });
    } finally {
      loadingDept.value = false;
    }
  };
  const getDataScopeDeptIdList = () => {
    if (props.dataScopeDeptIds) {
      props.dataScopeDeptIds.forEach((deptId: any) => {
        currentDataScopeDeptIds.value.push(deptId);
      });
    }
  };

  // 遍历deptTree部门树
  // 根据deptIdList确定权限节点决定勾选并筛去半勾选节点
  const traverseCheckAuth = (deptTree: any, deptIdList: string[]): number => {
    let result = 0;
    if (deptIdList.findIndex((e) => e === deptTree.id) > -1) {
      result = 1;
    }
    if (deptTree.children && deptTree.children.length > 0) {
      deptTree.children.forEach((n: any) => {
        // 筛去半勾选节点
        result = traverseCheckAuth(n, deptIdList) && result;
      });
    }
    if (result) {
      checkedNodeKeys.value = [...checkedNodeKeys.value, deptTree.id];
    }
    return result;
  };

  // 根据数据权限列表为部门树构建部门数据权限树
  const buildDataAuthTree = () => {
    checkedNodeKeys.value = [];
    deptTreeData.value.forEach((node) => {
      traverseCheckAuth(node, currentDataScopeDeptIds.value);
    });
  };

  watch(loadingDept, (value) => {
    if (!value) {
      buildDataAuthTree();
    }
  });
  defineExpose({ getDeptTree, getDataScopeDeptIdList });
  // 在<srcipt setup>的写法中，想要子组件中的方法可以被父组件调用，要通过defineExpose将方法暴露出去
</script>
